﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.Xna.Framework;
using WindowsGame1.gamePlugins.powerups;
using Microsoft.Xna.Framework.Content;
using WindowsGame1.gamePlugins.nxt;

namespace WindowsGame1.gamePlugins.renderer
{
    class Physics
    {
        public int scorePlayer1 = 0;
        public int scorePlayer2 = 0;
        public Powerups powerups;
        private Game1 gameProperties;
        private long lastCollision;

        // TODO: maak aparte class voor collisions
        public Physics(ContentManager content)
        {
            powerups = new Powerups(content);
        }

        /* Rendert alle objecten in de objectsx List 1 frame
         * @param gameTime: frametijd, geef deze door vanuit Game.Update(GameTime)
         * @param viewPort: width en height van de scene en dus de muren
         * @RETURN: alle gerenderde objecten
         */
        public List<PhysicsObject> renderframe(List<PhysicsObject> objectsx, GameTime gameTime, int[] viewPort, ControllerBridgeNXT nxt, Game1 game)
        {
            // maakt het mogelijk functies binnen Game1 aan te roepen
            gameProperties = game;

            // update frame powerups
            powerups.update(gameTime, this, objectsx, viewPort);

            for (int i = 0; i < objectsx.Count; i++)
            {
                PhysicsObject obj = objectsx[i];
                // als object een texture heeft EN visible is, dan physics
                if (obj != null && obj.texture != null && obj.visible)
                {
                    // basic physics
                    obj.speed.X *= obj.acceleration.X;
                    obj.speed.Y *= obj.acceleration.Y;
                    obj.rotation += obj.rotationSpeed;
                    obj.rotation *= obj.rotationAcceleration;
                    obj.oldPosition = obj.position;
                    // framespeed, die lijkt mij zo het beste
                    obj.position += obj.speed * (float) gameTime.ElapsedGameTime.TotalSeconds * 200;

                    // bepaal of er tegen een muur is gebotst
                    PhysicsObject botsObj = wallCollision(obj, viewPort, nxt);
                    if (botsObj != null) obj = botsObj;
                    // bepaal of er tegen een object is gebotst

                    PhysicsObject botsmetObj;
                    if (!obj.solidCollision) botsmetObj = collisionRenderer(obj, objectsx, nxt);
                    if (botsObj != null) obj = botsObj;
                    
                }
            }

            

            return objectsx;
        }

        public int[] getScore()
        {
            return new int[] {scorePlayer1, scorePlayer2};
        }


        /* Detecteer collision met andere objecten en weerkaats het object
         * @param viewPort: width en height van de scene en dus de muren
         * @param objectsx: de lijst van alle objecten
         * @RETURN: het weerkaatste object OF null
         */
        public PhysicsObject collisionRenderer(PhysicsObject obj, List<PhysicsObject> objectsx, ControllerBridgeNXT nxt)
        {
            // doe voor elk object
            for (int i = 0; i < objectsx.Count; i++)
            {
                PhysicsObject objx = objectsx[i];
                // wanneer het object niet NULL EN er een plaatje op zit
                if (objx != null && objx.texture != null && objx.name != obj.name)
                {
                    bool gebotst = collision(
                        // new Rectangle ( X, Y, Width, Height )
                        new Rectangle((int)obj.position.X, (int)obj.position.Y, (int)(obj.texture.Width * obj.scale), (int)(obj.texture.Height * obj.scale)),
                        new Rectangle((int)objx.position.X, (int)objx.position.Y, (int)(objx.texture.Width * objx.scale), (int)(objx.texture.Height * objx.scale))
                        );

                    if (gebotst)
                    {
                        if (obj.name == "pongball" && objx.name == "player1" || objx.name == "player2")
                        {
                            if ((ControllerBridgeNXT.getCurrentTimeMillis() - lastCollision) > 300)
                            {
                                obj.speed.X *= -1;
                                nxt.collision();
                            }
                            lastCollision = ControllerBridgeNXT.getCurrentTimeMillis();
                        }
                        else
                        {


                            /*if ((objx != objectsx[3]) && (objx != objectsx[4]) && (objx != objectsx[5]) && (objx != objectsx[6]) && (objx != objectsx[7]))
                            {
                                obj.speed.X *= -1;
                                nxt.collision();
                            }*/

                            // powerups.collision update objectsx
                            objectsx = powerups.collision(objectsx, obj, objx);
                        }
                    }
                }
            }
            return obj;
        }


        /* Detecteer collision met de muur en weerkaats het object
         * @param viewPort: width en height van de scene en dus de muren
         * @RETURN: het weerkaatste object OF null
         */
        public PhysicsObject wallCollision(PhysicsObject obj, int[] viewPort, ControllerBridgeNXT nxt)
        {
            Vector2 botsing = new Vector2(-1F, -1F);
            Vector2 min = Vector2.Zero;
            // TODO neem origin en scale mee in deze berekening
            Vector2 max = new Vector2(viewPort[0] - obj.texture.Width * obj.scale, viewPort[1] - obj.texture.Height * obj.scale);
            // EXTRA zorg dat de hoek van uitval aders is wanneer de bal draait

            if (obj.position.X > max.X)
            {
                botsing = new Vector2(max.X, obj.position.Y);
                obj.speed.X *= -1;
                obj.position.X = max.X;
                scorePlayer2++;
                scoreChanged(nxt);
            }
            else if (obj.position.X < min.X)
            {
                botsing = new Vector2(min.X, obj.position.Y);
                obj.speed.X *= -1;
                obj.position.X = min.X;
                scorePlayer1++;
                scoreChanged(nxt);
            }

            if (obj.position.Y > max.Y)
            {
                botsing = new Vector2(obj.position.X, max.Y);
                obj.speed.Y *= -1;
                obj.position.Y = max.Y;
            }
            else if (obj.position.Y < min.Y)
            {
                botsing = new Vector2(obj.position.X, min.Y);
                obj.speed.Y *= -1;
                obj.position.Y = min.Y;
            }

            // Er is geen botsing met de muren
            if (botsing.X == -1F) return null;
            //////////////////////////////////
            //
            // Hier kan nog iets gedaan worden
            // wanneer de muur wordt geraakt
            // (effect of dergelijke)
            //
            //////////////////////////////////
            
            // Er is een botsing met de muren
            return obj;
        }

        public bool collision(Rectangle objColl, Rectangle obj2)
        {
            Vector2 botsing = new Vector2(-1F, -1F);
            // EXTRA zorg dat de hoek van uitval aders is wanneer de bal draait
            return objColl.Intersects(obj2);
        }

        void scoreChanged(ControllerBridgeNXT nxt)
        {
            // zorg dat de bal weer in de midden begint
            nxt.scoreChanged(scorePlayer1, scorePlayer2);
            gameProperties.resetBall();
        }
    }
}
